<?php
use oxide\plugin\PluginAbstract;
use oxide\http\Context;
use oxide\ui\html;
use oxide\application\View;
use oxide\application\ViewController;
use oxide\util\Debug;
use module\content\model\Content;
use oxide\data\Connection;

define('EDUPLUGIN_DIR', dirname(__FILE__));
Debug::enable();

require (EDUPLUGIN_DIR . '/library/EduContentController.php');
require (EDUPLUGIN_DIR . '/library/EduAdminController.php');
require (EDUPLUGIN_DIR . '/library/EduUserController.php');
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

class EduPlugin extends PluginAbstract
{
	const 
		STATUS_INACTIVE = -9,		// user paid and attended course, and the course has ended
		STATUS_ADDED = -1,				// user registered for course
		STATUS_PAID = 0,				// user paid for course
		STATUS_ACTIVE = 1;			// user paid and attending course
	
	private
		$_email_from,
		$_email_registration;
	
	protected static
		$supportedTypes = array(),
		$courseStatus = array(
			 self::STATUS_INACTIVE	=> 'inactive',
			 self::STATUS_ADDED => 'added',
			 self::STATUS_PAID	=> 'paid',
			 self::STATUS_ACTIVE	=> 'active'
		);
	
	/**
	 *
	 * @param Context $context 
	 * @notifies 
	 * @listening  CommandInitialize, ContentDefaultViewEnd, AdminContentPostForm, 
	 *					AdminContentPostContentWillSave, UserDefaultAdminForm, UserDefaultAdminListQuery, 
	 *					UserDefaultRegisterForm, UserDefaultUpdateForm, UserDefaultRegisterUserDidSave, 
	 *					UserDefaultAdminPostUserWillSave, UserProfileContentEnd, UserDefaultRegisterForm,
	 *					UserDefaultRegisterUserDidSave, UserDefaultUpdateDidsave
	 */
	public function onInit(Context $context) 
	{	
		$this->register('CommandInitialize');
		
		// content module
		$this->register('ContentDefaultViewEnd');
		
		// admin content module
		$this->register('AdminContentPostForm');
		$this->register('AdminContentPostContentWillSave');
		
		// user admin module
		$this->register('UserDefaultAdminForm');
		$this->register('UserDefaultAdminListQuery');
		$this->register('UserDefaultAdminPostUserWillSave');
		
		// user module
		$this->register('UserProfileContentEnd');
		$this->register('UserDefaultRegisterForm', 'userFormUpdate');
		$this->register('UserDefaultUpdateForm', 'userFormUpdate');
		$this->register('UserDefaultRegisterUserDidSave', 'userMetadataFormUpdate');
		$this->register('UserDefaultUpdateDidsave', 'userMetadataFormUpdate');
	}
	
	/**
	 * get the plugin supported types (based on the setting in the config)
	 * @return array 
	 */
	public static function getSupportedTypes()
	{	
		return self::$supportedTypes;
	}
	
	/**
	 * set the suppported types
	 * @param array $supported_types 
	 */
	private function setSupportedTypes($supported_types)
	{
		self::$supportedTypes = $supported_types;
	}
	
	/**
	 * get available user section status
	 * @return array
	 */
	public static function getAvailableUserSectionStatus()
	{
		return self::$courseStatus;
	}
	
	
	/**
	 * get the string status text based on the index
	 * @param int $index
	 * @return string 
	 */
	public static function getStringForSectionStatus($index)
	{
		if(isset(self::$courseStatus[$index])) {
			return self::$courseStatus[$index];
		}
		
		return '[unknown]';
	}
	
	/**
	 *
	 * @staticvar null $controller
	 * @return \EduContentController 
	 */
	protected function getContentController()
	{
		static $controller = null;
		if($controller === null) {
			$controller = new EduContentController($this->_context);
		}
		
		return $controller;
	}
	
	protected function getAdminController()
	{
		static $controller = null;
		if ($controller === null) {
			$controller = new EduAdminController();
		}
		
		return $controller;
	}
	
	protected function getUserController()
	{
		static $controller = null;
		if ($controller === null) {
			$controller = new EduUserController();
		}
		
		return $controller;
	}
	
	/** 
	 * listing for /content/course/register
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onCommandInitialize($event, \oxide\application\ActionController $sender, $args = null)
	{
		// get the config from the plugin
		$config = $this->getConfig();
		
		// retrieve the confg values from the edu section
		$support_content_types = $config->getSectionValue('edu', 'supported_content_types');
		$email_from = $config->getSectionValue('edu', 'email_from');
		$email_registration = $config->getSectionValue('edu', 'email_registration');
		
		// check if the fields are not available
		if((bool)$support_content_types == false || (bool)$email_from == false || (bool)$email_registration == false) {
			// if true, throw an exception
			throw new Exception("Please refer to doc for Edu configuration.");
		} else {
			// if false, store subjects
			$support_types = explode(',', $support_content_types);
			// store the various values
			$this->setSupportedTypes($support_types);
			$this->_email_from = $email_from;
			$this->_email_registration = $email_registration;
		}
		
		
		// get the route
		$route = $this->_context->route;
		$auth = $this->_context->getAuth();
		
		// only interested in content module
		if($route->module != 'content') return;
		
		// check for only supported content type
		$content_type = @$route->params[0];
		if(in_array($content_type, self::getSupportedTypes())) {

			// content module
			$this->register('ModuleContentInfoRenderContentEnd');
		}

		// registration process
		// initialize vars
		$context = $this->_context;
		$message = "";

		// check on user's landing page ie. listening for /content/course/register
		if ($route->action == 'course' && $route->params[0] == 'register') {
			
			// ensure that the content pk is available from the param[1]
			// user is already logged in and
			// the content to register is valid, else throw exception
			if (empty($route->params[1]) || !$auth->hasIdentity()) {
				throw new Exception('Invalid Page Access', 901);
			}
			
			$content_pk = $route->params[1];
			$content = \module\content\model\Content::find($content_pk);
			if (!$this->_validateContentToRegister($content)) {
				throw new Exception('Invalid Page Access', 901);
			}
			
			// confirmation form
			$user = $auth->getIdentity();
			$metadata = $content->metadata();
		
			$form = new html\Form('post');
			$form->addControl(new html\StaticControl('p', 'course', $content->title, 'Course Title'));
			$form->addControl(new html\StaticControl('p', 'price', $metadata->EduPlugin_cost, 'Price'));
			$form->addControl(new html\TextareaControl('comment_message', null, 'Comment/Message:'));
			$payment_options = array('cash' => 'Cash', 'cheque' => 'Cheque', 'transfer' => 'Bank Transfer');
			$form->addControl(new html\SelectControl('payment_method', null, 'Payment Method:', null, $payment_options));
			$form->addControl(new html\ButtonControl('submit', 'submit', null, 'Confirm'));

			// check if user has previously made a registration for the course
			$course = \module\content\model\ContentUserExtension::findByContent_pkAndUser_pk($content_pk, $user->user_pk);

			// the different statuses for the registering a course record by user
			// 1. the user has registered + paid for the course + course starts (Active) - prompt go to classroom msg
			// 2. the user has registered + not paid for the course (Added) - prompt make payment msg
			// 3. the user has paid for course, but course not started yet (Paid) - prompt class not started yet
			// 4. the user has completed the course (Inactive)
			// 5. the user not registered (NULL) - update status
			// 6. there is no record for the course (EMPTY/No record) - save new
			


			// status 1. the user has registered + paid for the course (1) - prompt go to classroom msg
			if ($course->edu_status == self::STATUS_ACTIVE) {
				$message = "You have already registered and made payment for this course, please proceed to the classroom.";
			}

			// status 2. the user has registered + not paid for the course - prompt make payment msg
			if ($course->edu_status == self::STATUS_ADDED) {
				$message = "You have already registered for this course previously, please proceed to make the payment.";
			} 
			
			// status 3. the user has paid for course, but course not started yet (Paid) - prompt class not started yet
			if ($course->edu_status == self::STATUS_PAID) {
				$message = "You have already registered and made payment for this course, please wait for the class to start.";
			}
			
			// status 4. the user has completed the course (Inactive)
			if ($course->edu_status == self::STATUS_INACTIVE) {
				$message = "You have already completed the course.";
			}
			
			if ($form->isSubmit()) {
				$result = null;
				$values = $form->process($result);

				// status 5 & status 6
				if (is_null($course->edu_status) || empty($course)) {

					// if true, send confirmation email
					$registration_success = $this->_registerCourse($course, $user, $values);

					$payment_method = $values['payment_method'];
					$comment_message = $values['comment_message'];

					// send email confirmation to user and admin upon successfully registration of course
					$send_from = $this->_email_from;
					$send_to = $user->email;
					$send_subject = "Course Registeration Successful";

					$script = EDUPLUGIN_DIR . '/email-register-student.phtml';
					$view = new View($script);
					$view->assign('cost', $metadata->EduPlugin_cost);
					$view->assign('title', $content->title);
					$view->assign('payment_method', $payment_method);
					$view->assign('comment', $comment_message);
					$send_message = $view->render();
					oxide\util\Mailer::send($send_from, $send_to, $send_subject, $send_message);
					
					$send_to = $this->_email_registration;
					$send_subject = "New Course Registration";

					$script = EDUPLUGIN_DIR . '/email-register-admin.phtml';
					$view = new View($script);
					$view->assign('username', $user->username);
					$view->assign('title', $content->title);
					$view->assign('payment_method', $payment_method);
					$view->assign('comment', $comment_message);
					$send_message = $view->render();
					oxide\util\Mailer::send($send_from, $send_to, $send_subject, $send_message);

					// registration confirmation page
					$message = "Thank you very much. You are registered for the course ({$content->title}), please proceed to make the payment.";
				}


				// render the script within the template
				// setup the view with script
				$script = EDUPLUGIN_DIR .'/register-confirmation.phtml';
				$view = new View($script);
				$view->assign('message', $message);
				$view->assign('user', $user);
				$view->setIdentifier(PHPOXIDE_CONTENT_VIEW);


				$viewController = $sender->getViewController();
				$context->getResponse()->addBody($viewController->render($view));
				$context->getResponse()->send();
				exit();
			
			}

			$script = EDUPLUGIN_DIR .'/confirmation.phtml';
			$view = new View($script);
			$view->assign('user', $user);
			$view->assign('form', $form);
			$view->setIdentifier(PHPOXIDE_CONTENT_VIEW);
						
			$viewController = $sender->getViewController();
			$context->getResponse()->addBody($viewController->render($view));
			$context->getResponse()->send();
			exit;
		} else {
		}
				
	}
	
	/**
	 * register user for the course content (add payment method, and set status)
	 * @param type $content
	 * @param type $user
	 * @return boolean 
	 */
	private function _registerCourse($content, $user, $values = null)
	{
		// status 5. the user has visited the course, but not registered (NULL) - update status, then prompt make payment msg
		// check if the status of user's record is NULL, if true get the current course content
		if (is_null($content->edu_status)) {
			$content_user_ext = $content;
		}
		
		// status 6. there is no record for the course (EMPTY/No record) - save new, then prompt make payment msg
		// check if there is no record, if true, then save the record as a new record
		if (empty($content)) {
			$content_user_ext = new \module\content\model\ContentUserExtension();
			$content_user_ext->content_pk = $content->content_pk;
			$content_user_ext->user_pk = $user->user_pk;
		}
		
		// add the payment type, set the status as registered/ but not paid and /added, and save/update
		$content_user_ext->edu_payment_type = $values['payment_method'];
		$content_user_ext->edu_status = self::STATUS_ADDED;
		$content_user_ext->save();
	}
	
	/**
	 * check if the course to register is valid
	 * ie. required to fulfill the 3 conditions of:
	 *		1. content is available
	 *		2. content pk is a section
	 *		3. content status is active
	 * @param type $content_pk 
	 */
	private function _validateContentToRegister($content)
	{
		if (empty($content) || ($content->content_type != 'section') || ($content->status != self::STATUS_ACTIVE)) {
			return false;
		}
		return true;
	}
	
	/**
	 * check on the supported type and user authentication before the view is rendered
	 * @param type $event
	 * @param \oxide\application\ActionController $sender
	 * @param type $args
	 * @throws Exception 
	 */
	public function onContentDefaultViewEnd($event, \oxide\application\ActionController $sender, $args = null)
	{
		$auth = $this->_context->getAuth();
		$route = $this->_context->route;
		
		$content = $sender->getView()->content;
		
		$this->getContentController()->contentViewValidation($content, $auth);

	}
	
	/**
	 * rendering the sub content when loading the module content
	 * 
	 * only handles "view" action
	 * will list all subcotents for the viewed content
	 * @param type $event
	 * @param type $sender
	 * @param type $content 
	 */
	public function onModuleContentInfoRenderContentEnd($event, $sender, $content = null)
	{
		// initialize vars
		$route = $this->getContext()->route;
		$action = $route->action;
		
		// check if current view is on action view
		// if true, get the content controller to display the sub content action
		if($action != 'view') return;
		$this->getContentController()->subContentAction($content);
	}
	
	/**
	 * render the additional fieldset for User Administration
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onUserDefaultAdminForm($event, $sender, $args)
	{	
		$this->getAdminController()->formAdminUserEntry($args);	
	}
	
	/**
	 * save the updated form values of registration info fieldset
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onUserDefaultAdminPostUserWillSave($event, $sender, $args)
	{
		$this->getAdminController()->saveRegistrationInfoValues($args);
	}
		
	/**
	 * in user admin listing, display the listing based on the specified conditions
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onUserDefaultAdminListQuery($event, $sender, $args = null)
	{
		// initialize
		$request = $this->_context->getRequest();
		$edu_section = $request->getQuery('edu_section', null);
		$edu_status = $request->getQuery('edu_status', null);
		
		if (isset($edu_section) || isset($edu_status)) {
			$this->getAdminController()->queryUserAdminListQuery($args, $request);
		}
	}
	
	/**
	 * in administration content entry, display the additional fields if the content type is section
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onAdminContentPostForm($event, $sender, $args)
	{
		$route = $this->_context->route;
		$content = $args['content'];
		
		// get the content type for new post/update existing post
		// new post - does not have $content->content_type, hence get the content type from params
		// existing post - have $content->content_type
		if ($route->params[0]) { 
			$content_type = $route->params[0]; 
		} else {
			$content_type = $content->content_type;
		}
		
		// if it is section, display the Section fieldset
		if ($content_type == 'section') {
			$this->getAdminController()->formSectionContent($args);
		} 
		
		// if it is anything within the supported types, yet not course and section
		else if ($content_type != 'course' && in_array($content_type, self::getSupportedTypes())) {
			$this->getAdminController()->formInstructorContent($args);
		}

	}
	

	/**
	 * this will manipulate any field values to before saving
	 * e.g description value will be saved to content filtered
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onAdminContentPostContentWillSave($event, $sender, $args)
	{
		$route = $this->_context->route;
		$content = $args['content'];
		
		// get the content type for new post/update existing post
		// new post - does not have $content->content_type, hence get the content type from params
		// existing post - have $content->content_type
		if ($route->params[0]) { 
			$content_type = $route->params[0]; 
		} else {
			$content_type = $content->content_type;
		}
		
		if ($content_type != 'section' && $content_type != 'course' && in_array($content_type, self::getSupportedTypes())) {
			$this->getAdminController()->willSaveInstructorContent($args);
		}
	}
	
	/**
	 * displaying registered courses in user profile
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onUserProfileContentEnd($event, $sender, $args)
	{
		// initialize vars
		$user = $args;

		$this->getUserController()->userProfile($user);
	}	
	
	/**
	 * Setting up the user form update for registration and update info
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function userFormUpdate($event, $sender, $args)
	{
		// initialize the vars with args
		$user = $args['user'];
		$form = $args['form'];

		$this->getUserController()->userFormUpdate($form, $user);
	}

	/**
	 * save/update user metadata during registration and update info
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function userMetadataFormUpdate($event, $sender, $args)
	{
		// initialize the vars with args
		$user = $args['user'];
		$values = $args['values'];
	
		$this->getUserController()->userMetaFormUpdate($user, $values);
	}
	
	
}
?>